#include "common.h"
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QEventLoop>
#include <QDialog>
#include <QLabel>
#include <QMovie>
#include <QWidget>
#include <QHBoxLayout>
#include <QHttpMultiPart>
#include <stdio.h>

class Loading : public QDialog
{
public:
    Loading(QWidget* parent) :
        QDialog(parent),
        load(this),
        label(this),
        movie(":/image/loading.gif")
    {
        load.setMovie(&movie);
        load.setSizeIncrement(QSize(16, 16));
        movie.start();
        label.setText(_T("加载中..."));
        layout.setMargin(3);
        layout.addWidget(&load);
        layout.addWidget(&label);
        setLayout(&layout);

        setWindowOpacity(1);
        setWindowFlags(Qt::FramelessWindowHint);
        setWindowModality(Qt::ApplicationModal);
        setAttribute(Qt::WA_TranslucentBackground, true);

        QRect rtParent = parent->rect();
        QRect rtSelf = rect();

        move((rtParent.width() - rtSelf.width()) / 2,
             (rtParent.height() - rtSelf.height()) / 2);
        parent->setDisabled(true);
    }

public:
    virtual void	closeEvent(QCloseEvent * event)
    {
         parentWidget()->setDisabled(false);
    }

private:
    QLabel      label;
    QLabel      load;
    QMovie      movie;
    QHBoxLayout layout;
};

/*
 * get/post http
 */
bool ad::http_request(const char* url, QString &err,
                     JSONNode *json /* = NULL */,
                     QWidget* parent/* = NULL*/,
                     QByteArray* post /*= NULL*/)
{
    QNetworkAccessManager       manager;
    QNetworkReply*              reply       = NULL;
    QEventLoop                  loop;
    Loading                     *load       = NULL;
    QNetworkRequest             request;
    QUrl                        qurl;

    qurl.setEncodedUrl(url, QUrl::StrictMode);
    request.setUrl(qurl);
    // send request
    if(NULL != post)
    {
        request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
        request.setHeader(QNetworkRequest::ContentLengthHeader, post->length());
        reply = manager.post(request, *post);
    }
    else
    {
        reply = manager.get(request);
    }

    if(NULL == reply)
    {
        err = _T("构建对像失败");
        return false;
    }

    // show loading
    if(NULL != parent)
    {
        load = new Loading(parent);
        QObject::connect(reply, SIGNAL(finished()), load, SLOT(close()));
        QObject::connect(reply, SIGNAL(destroyed()), load, SLOT(close()));
        load->exec();
        load->close();
        load->deleteLater();
    }
    else
    {
        // wait request;
        QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
        loop.exec(QEventLoop::ExcludeUserInputEvents);
    }

    if(reply->error())
    {
        err = _T("网络连接失败");
        reply->deleteLater();
        return false;
    }

    // check response is json
    if("application/json" != reply->header(QNetworkRequest::ContentTypeHeader))
    {
        err = _T("服务器内部错误");
        reply->deleteLater();
        return false;
    }

    // create json
    QByteArray          ba = reply->readAll();

    reply->deleteLater();
    if(NULL != json)
    {
        if(false == ad::json_parse(*json, ba.data(), &err))
        {
            return false;
        }

        if( 0 != ad::json_get_int(*json, "errno") )
        {
            err = ad::json_get_string(*json, "error", L"未知错误");
            return false;
        }

        return true;
    }

    // only get response is success
    JSONNode    node;

    if(false == ad::json_parse(node, ba.data(), &err))
    {
        return false;
    }

    if( 0 != ad::json_get_int(node, "errno") )
    {
        err = ad::json_get_string(node, "error", L"未知错误");
        return false;
    }

    return true;
}

char* ad::get_file_data(const char *filepath)
{
    FILE*       file        = fopen(filepath, "rb");
    unsigned long size;

    if(NULL == file)
    {
        return NULL;
    }

    fseek(file, 0L, SEEK_END);
    size = ftell(file);
    fseek(file, 0L, SEEK_SET);
    if(0 == size)
    {
        fclose(file);
        return NULL;
    }

    char*      buf = (char *)malloc(size + 1);
    if(NULL == buf)
    {
        fclose(file);
        return NULL;
    }

    fread(buf, size, 1, file);
    fclose(file);
    buf[size] = 0;
    return buf;
}

bool ad::json_parse(JSONNode &json, json_string str, QString *err)
{
    try
    {
        json = libjson::parse(str);
        return true;
    }
    catch(std::invalid_argument& arg)
    {
        if(NULL != err)
        {
            *err = _T("错语的JSON格式");
        }
    }
    catch(...)
    {
        if(NULL != err)
        {
            *err = _T("未知错误");
        }
    }

    return false;
}

/*
 * 检测json是否存在指定的数据
 */
bool ad::json_check(JSONNode &json, json_string name, char type)
{
    JSONNode::iterator      fd = json.find(name);

    if(json.end() == fd || fd->type() != type)
    {
        return false;
    }

    return true;
}

bool ad::json_check(JSONNode &json, json_index_t index, char type)
{
    if(index >= json.size()
            || json[index].type() != type)
    {
        return false;
    }

    return true;
}

bool ad::json_is_string(JSONNode &json, json_string name)
{
    return ad::json_check(json, name, JSON_STRING);
}

bool ad::json_is_array(JSONNode &json, json_string name)
{
    return ad::json_check(json, name, JSON_ARRAY);
}

bool ad::json_is_array(JSONNode &json, json_index_t index)
{
    return ad::json_check(json, index, JSON_ARRAY);
}

int ad::json_get_int(JSONNode &json, json_string name, int def/* = 0*/)
{
    if( false == ad::json_check(json, name, JSON_NUMBER) )
    {
        return def;
    }

    return json[name].as_int();
}

int ad::json_get_int(JSONNode &json, json_index_t index, int def/* = 0*/)
{
    if( false == ad::json_check(json, index, JSON_NUMBER) )
    {
        return def;
    }

    return json[index].as_int();
}

float ad::json_get_float(JSONNode &json, json_string name, float def/* = 0.0*/)
{
    if( false == ad::json_check(json, name, JSON_NUMBER) )
    {
        return def;
    }

    return json[name].as_float();
}

QString ad::json_get_string(JSONNode &json, json_string name, wchar_t* def/* = ""*/)
{
    if( false == ad::json_check(json, name, JSON_STRING) )
    {
        return QString::fromWCharArray(def);
    }

    return QString::fromUtf8(json[name].as_string().c_str());
}

QString ad::json_get_string(JSONNode &json, json_index_t index, wchar_t* def/* = ""*/)
{
    if( false == ad::json_check(json, index, JSON_STRING) )
    {
        return QString::fromWCharArray(def);
    }

    return QString::fromUtf8(json[index].as_string().c_str());
}

bool ad::json_get_node(JSONNode &json, json_string name, JSONNode &node)
{
    if( false == ad::json_check(json, name, JSON_NODE) )
    {
        return false;
    }

    node = json[name].as_node().duplicate();
    return true;
}
